import sys
import os
import signal
import subprocess
import re
import xbmc
import xbmcaddon
import xbmcgui
import threading
import time, datetime
import commands
import urllib2
from xml.dom import minidom

#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
TVHEADEND_URL = 'http://localhost:9981/status.xml'
LOG_FILE = '/storage/.xbmc/userdata/addon_data/service.system.wakeup/wakeup.log'
__settings__   = xbmcaddon.Addon(id='service.system.wakeup')
__cwd__        = __settings__.getAddonInfo('path')
SHUTDOWN_SCRIPT=xbmc.translatePath( os.path.join( __cwd__, "shutdown.sh") )

openelec_user = __settings__.getSetting("username")
openelec_pw = __settings__.getSetting("password")
WAITBEFORESHUTDOWN = int(float(__settings__.getSetting("waitbeforeshutdown")))
WAKEBEFORERECORDING = int(float(__settings__.getSetting("wakeforerecording")))

class MyClass(xbmcgui.Window):
  def __init__(self):
    self.writeToLogFile("init");
    self.strActionInfo = xbmcgui.ControlLabel(100, 120, 800, 400, '', 'font13', '0xFFFF00FF')
    self.addControl(self.strActionInfo)
    self.strActionInfo.setLabel('Determining recording status....')
    self.button0 = xbmcgui.ControlButton(350, 500, 200, 50, "Return to XBMC")
    self.addControl(self.button0)
    self.button1 = xbmcgui.ControlButton(700, 500, 200, 50, "Shutdown XBMC")
    self.addControl(self.button1)
    self.setFocus(self.button0)
    self.button0.controlRight(self.button1)
    self.button0.controlLeft(self.button1)
    self.button1.controlRight(self.button0)
    self.button1.controlLeft(self.button0)
    self.timerMsg = threading.Timer(5, self.checkRecording)
    self.timerMsg.start()
 
  def onAction(self, action):
    if action == ACTION_PREVIOUS_MENU:
      self.timerMsg.cancel()
      self.close()
 
  def onControl(self, control):
    if control == self.button0:
      self.timerMsg.cancel()
      self.close()
    if control == self.button1:
      self.message('Are you sure you want to shutdown with active recordings?')
      self.timerMsg.cancel()

  def message(self, message):
    dialog = xbmcgui.Dialog()
    if dialog.yesno("PVRUptime", message):
      #suspend
      self.close()

  def findThisProcess(self, process_name ):
    ps     = subprocess.Popen("ps -eaf | grep "+process_name, shell=True, stdout=subprocess.PIPE)
    output = ps.stdout.read()
    ps.stdout.close()
    ps.wait()
    return output

  def writeToLogFile(self, message):
    if os.path.isfile(LOG_FILE) == False:
      logFile = open(LOG_FILE, 'w')
    else:    
      logFile = open(LOG_FILE, 'r+')
      logFile.seek(0,2)
    logFile.write(str(datetime.datetime.now()) + ": " + message +'\n')
    logFile.close()

  def checkProcess(self, processname):
    processExists = "False"
    processList = os.popen("ps xa")
    if processList:
      for line in processList:
        fields = line.split()
        pid = fields[0]
        process = fields[4]
        if process.find(processname) > 0:
          processExists = "True"
          break
    return processExists
	
  def checkRecording(self):
    closestRecordingDateTimeStart = None
    closestRecordingDateTimeEnd = None
    closestRecordingTitle = None
    currentlyRecording = False
    difference = None
    UTCTimeDelta = datetime.timedelta(hours=8)
    currentTime = datetime.datetime.now()
    dialog = xbmcgui.Dialog()

    password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
    password_mgr.add_password(None, TVHEADEND_URL, openelec_user, openelec_pw)
    handler = urllib2.HTTPBasicAuthHandler(password_mgr)
    opener = urllib2.build_opener(handler)
    opener.open(TVHEADEND_URL)
    urllib2.install_opener(opener)
    f = urllib2.urlopen(TVHEADEND_URL)
    link = f.read()
    xmldoc = minidom.parseString(link)
    f.close()
    
    # If there is a 'next' tag in the XML, then there is no recording happening    
    nextRecordingNode = xmldoc.getElementsByTagName('next')
    
    if nextRecordingNode:
      minutesUntilNextRecording = int(nextRecordingNode[0].childNodes[0].data) 
      closestRecordingDateTimeStart = currentTime + datetime.timedelta(minutes=minutesUntilNextRecording) 
    else:
      closestRecordingDateTimeStart = None 
      recordingNodes = xmldoc.getElementsByTagName('recording')
      if recordingNodes:
        for recordingnode in recordingNodes:
          nextRecordingDateTimeStart = datetime.datetime.fromtimestamp(float(recordingnode.getElementsByTagName('start')[0].getElementsByTagName('unixtime')[0].childNodes[0].data))
          nextRecordingDateTimeExtraStart = recordingnode.getElementsByTagName('start')[0].getElementsByTagName('extra_start')[0].childNodes[0].data
          nextRecordingDateTimeStartUTC = nextRecordingDateTimeStart - datetime.timedelta(minutes=int(nextRecordingDateTimeExtraStart))
          
          nextRecordingDateTimeEnd = datetime.datetime.fromtimestamp(float(recordingnode.getElementsByTagName('stop')[0].getElementsByTagName('unixtime')[0].childNodes[0].data))
          nextRecordingDateTimeExtraEnd = recordingnode.getElementsByTagName('stop')[0].getElementsByTagName('extra_stop')[0].childNodes[0].data
          nextRecordingDateTimeEndUTC = nextRecordingDateTimeEnd + datetime.timedelta(minutes=int(nextRecordingDateTimeExtraEnd))
          
          nextRecordingTitle = recordingnode.getElementsByTagName('title')[0].childNodes[0].data
          
          self.strActionInfo.setLabel(str(nextRecordingDateTimeStartUTC) + ", " + str(nextRecordingDateTimeEndUTC) +", " + str(currentTime))
          
          if nextRecordingDateTimeStartUTC < nextRecordingDateTimeEndUTC:
            if nextRecordingDateTimeStartUTC > currentTime:
              if currentlyRecording == False:
                if closestRecordingDateTimeStart is None: 
                  closestRecordingDateTimeStart = nextRecordingDateTimeStartUTC
                  closestRecordingDateTimeEnd = nextRecordingDateTimeEndUTC
                  closestRecordingTitle = nextRecordingTitle
                else:
                  if closestRecordingDateTimeStart > nextRecordingDateTimeStartUTC:
                    closestRecordingDateTimeStart = nextRecordingDateTimeStartUTC
                    closestRecordingDateTimeEnd = nextRecordingDateTimeEndUTC
                    closestRecordingTitle = nextRecordingTitle
            else:
              if nextRecordingDateTimeEndUTC > currentTime:
                if currentlyRecording == False:
                  closestRecordingDateTimeStart = nextRecordingDateTimeStartUTC
                  closestRecordingDateTimeEnd = nextRecordingDateTimeEndUTC
                  closestRecordingTitle = nextRecordingTitle
                  currentlyRecording = True
                else:
                  closestRecordingTitle = closestRecordingTitle + "[CR]" + nextRecordingTitle
                  if nextRecordingDateTimeEndUTC > closestRecordingDateTimeEnd:
                    closestRecordingDateTimeStart = nextRecordingDateTimeStartUTC
                    closestRecordingDateTimeEnd = nextRecordingDateTimeEndUTC
    if currentlyRecording == True:
      difference = closestRecordingDateTimeEnd - currentTime
      #handling german special characters
      try:
        closestRecordingTitle = closestRecordingTitle.encode("utf-8")
      except Exception:
        self.writeToLogFile("Error occurred encoding title");
      outputMessage = "Currently recording [CR]" + closestRecordingTitle + "[CR]for another " + str(abs(difference.seconds)/60) + " minutes [CR]until " + str(closestRecordingDateTimeEnd)
      self.writeToLogFile(outputMessage)
      self.strActionInfo.setLabel(outputMessage)
      self.timerMsg = threading.Timer(30, self.checkRecording)
      self.timerMsg.start()
    else:
      if closestRecordingDateTimeStart is None:
        closestRecordingDateTimeStart = currentTime + datetime.timedelta(hours=4)
      difference = closestRecordingDateTimeStart - currentTime
      # determine if the next recording is > threshold minutes away
      if abs(difference.seconds) > WAITBEFORESHUTDOWN:
        wakeupDateTimeUTC = closestRecordingDateTimeStart - datetime.timedelta(seconds=WAKEBEFORERECORDING)
        outputMessage = "Next recording more than " + str(WAITBEFORESHUTDOWN) + " seconds away[CR]shutting down with restart in " + str(abs(difference.seconds)/60) + " minutes, at " + str(wakeupDateTimeUTC)
        self.writeToLogFile(outputMessage)
        self.strActionInfo.setLabel(outputMessage)
        wakeupCommand = 'sh ' + SHUTDOWN_SCRIPT + ' ' + str(time.mktime(wakeupDateTimeUTC.timetuple())) + ' &> ' + LOG_FILE
        self.writeToLogFile('Invoking Shutdown: ' + wakeupCommand);
        os.system(wakeupCommand)
        self.strActionInfo.setLabel("Determining recording status...")
        currentTime = datetime.datetime.now()
        difference = time.mktime(wakeupDateTimeUTC.timetuple()) - time.mktime(currentTime.timetuple()) 
        outputMessage = "Difference = " + str(abs(difference)) 
        self.writeToLogFile(outputMessage)
        if abs(difference) > 60:
          outputMessage = "Appeared to have been woken by user (difference between wakuptime and currenttime = " + str(abs(difference)) + ")"
          self.writeToLogFile(outputMessage)
          outputMessage = "Exiting pvruptime back to XBMC"
          self.writeToLogFile(outputMessage)
          self.timerMsg.cancel()
          self.close()
        else:
          outputMessage = "Appeared to have been woken to record (difference between wakuptime and currenttime = " + str(abs(difference)) + ")"
          self.writeToLogFile(outputMessage)
          self.timerMsg = threading.Timer(30, self.checkRecording)
          self.timerMsg.start()
      else:
        outputMessage = "Next recording less than " + str(WAITBEFORESHUTDOWN/60) + " minutes away, staying awake"
        self.strActionInfo.setLabel(outputMessage)
        self.writeToLogFile(outputMessage)
        self.timerMsg = threading.Timer(30, self.checkRecording)
        self.timerMsg.start()

  def shutdown(self):
    wakeupCommand = SHUTDOWN_SCRIPT + ' ' + str(time.mktime(wakeupDateTimeUTC.timetuple()))
    self.writeToLogFile('Shutdown invoked: ' + wakeupCommand);
    os.system(wakeupCommand)


mydisplay = MyClass()
mydisplay .doModal()
del mydisplay

